package snowflake

import (
	"fmt"
	"sync"
	"time"

	"github.com/pkg/errors"
)

const (
	maxWorkID   = uint64(-1 ^ (-1 << 5))
	maxCenterID = uint64(-1 ^ (-1 << 5))
	maxSeqNum   = uint64(-1 ^ (-1 << 12))
)

type Options struct {
	WorkID       uint64
	DataCenterID uint64
}

type Snowflake struct {
	sync.Mutex
	workID       uint64
	dataCenterID uint64
	seqNum       uint64
	lastMilli    uint64
}

// GetUID 得到全局唯一ID int64类型
// 首位0(1位) + 毫秒时间戳(41位) + 数据中心标识(5位) + 工作机器标识(5位) + 自增id(12位)
// 时间可以保证400年不重复
// 数据中心和机器标识一起标识节点，最多支持1024个节点
// 每个节点每一毫秒能生成最多4096个id
// 63      62            21            16        11       0
// +-------+-------------+-------------+---------+--------+
// | 未使用 | 毫秒级时间戳 | 数据中心标识 | 工作机器 | 自增id |
// +-------+-------------+-------------+---------+--------+
func (s *Snowflake) GetUUID() uint64 {
	s.Lock()
	defer s.Unlock()
	now := s.getUnixMill()
	if now != s.lastMilli {
		s.seqNum = 0
		s.lastMilli = now
	} else {
		s.seqNum++
		if s.seqNum > maxSeqNum {
			for now <= s.lastMilli {
				now = s.getUnixMill()
			}
		}
	}
	return now<<22 | s.dataCenterID<<17 | s.workID<<12 | (s.seqNum & maxSeqNum)
}

func (s *Snowflake) getUnixMill() uint64 {
	return uint64(time.Now().UnixNano() / int64(time.Millisecond))
}

//初始化节点标识
func New(o *Options) (*Snowflake, error) {
	if maxWorkID < o.WorkID {
		return nil, errors.New(fmt.Sprintf("[snowflake] work_id must less than %v", maxWorkID))
	}
	if maxCenterID < o.DataCenterID {
		return nil, errors.New(fmt.Sprintf("[snowflake] work_id must less than %v", maxCenterID))
	}
	return &Snowflake{
		workID:       o.WorkID,
		dataCenterID: o.DataCenterID,
	}, nil
}
